/**
 *
 * @author jack870131
 */
public class RedBlackBST {

	private final int R = 0;
	private final int B = 1;

	private class Node {

		int key = -1, color = B;
		Node left = nil, right = nil, p = nil;

		Node(int key) {
			this.key = key;
		}
	}

	private final Node nil = new Node(-1);
	private Node root = nil;

	public void printTree(Node node) {
		if (node == nil) {
			return;
		}
		printTree(node.left);
		System.out.print(((node.color == R) ? " R " : " B ") + "Key: " + node.key + " Parent: " + node.p.key + "\n");
		printTree(node.right);
	}

	public void printTreepre(Node node) {
		if (node == nil) {
			return;
		}
		System.out.print(((node.color == R) ? " R " : " B ") + "Key: " + node.key + " Parent: " + node.p.key + "\n");
		printTree(node.left);
		printTree(node.right);
	}

	private Node findNode(Node findNode, Node node) {
		if (root == nil) {
			return null;
		}
		if (findNode.key < node.key) {
			if (node.left != nil) {
				return findNode(findNode, node.left);
			}
		} else if (findNode.key > node.key) {
			if (node.right != nil) {
				return findNode(findNode, node.right);
			}
		} else if (findNode.key == node.key) {
			return node;
		}
		return null;
	}

	private void insert(Node node) {
		Node temp = root;
		if (root == nil) {
			root = node;
			node.color = B;
			node.p = nil;
		} else {
			node.color = R;
			while (true) {
				if (node.key < temp.key) {
					if (temp.left == nil) {
						temp.left = node;
						node.p = temp;
						break;
					} else {
						temp = temp.left;
					}
				} else if (node.key >= temp.key) {
					if (temp.right == nil) {
						temp.right = node;
						node.p = temp;
						break;
					} else {
						temp = temp.right;
					}
				}
			}
			fixTree(node);
		}
	}

	private void fixTree(Node node) {
		while (node.p.color == R) {
			Node y = nil;
			if (node.p == node.p.p.left) {
				y = node.p.p.right;

				if (y != nil && y.color == R) {
					node.p.color = B;
					y.color = B;
					node.p.p.color = R;
					node = node.p.p;
					continue;
				}
				if (node == node.p.right) {
					node = node.p;
					rotateLeft(node);
				}
				node.p.color = B;
				node.p.p.color = R;
				rotateRight(node.p.p);
			} else {
				y = node.p.p.left;
				if (y != nil && y.color == R) {
					node.p.color = B;
					y.color = B;
					node.p.p.color = R;
					node = node.p.p;
					continue;
				}
				if (node == node.p.left) {
					node = node.p;
					rotateRight(node);
				}
				node.p.color = B;
				node.p.p.color = R;
				rotateLeft(node.p.p);
			}
		}
		root.color = B;
	}

	void rotateLeft(Node node) {
		if (node.p != nil) {
			if (node == node.p.left) {
				node.p.left = node.right;
			} else {
				node.p.right = node.right;
			}
			node.right.p = node.p;
			node.p = node.right;
			if (node.right.left != nil) {
				node.right.left.p = node;
			}
			node.right = node.right.left;
			node.p.left = node;
		} else {
			Node right = root.right;
			root.right = right.left;
			right.left.p = root;
			root.p = right;
			right.left = root;
			right.p = nil;
			root = right;
		}
	}

	void rotateRight(Node node) {
		if (node.p != nil) {
			if (node == node.p.left) {
				node.p.left = node.left;
			} else {
				node.p.right = node.left;
			}

			node.left.p = node.p;
			node.p = node.left;
			if (node.left.right != nil) {
				node.left.right.p = node;
			}
			node.left = node.left.right;
			node.p.right = node;
		} else {
			Node left = root.left;
			root.left = root.left.right;
			left.right.p = root;
			root.p = left;
			left.right = root;
			left.p = nil;
			root = left;
		}
	}

	void transplant(Node target, Node with) {
		if (target.p == nil) {
			root = with;
		} else if (target == target.p.left) {
			target.p.left = with;
		} else
			target.p.right = with;
		with.p = target.p;
	}

	Node treeMinimum(Node subTreeRoot) {
		while (subTreeRoot.left != nil) {
			subTreeRoot = subTreeRoot.left;
		}
		return subTreeRoot;
	}

	boolean delete(Node z) {
		if ((z = findNode(z, root)) == null)
			return false;
		Node x;
		Node y = z;
		int yorigcolor = y.color;

		if (z.left == nil) {
			x = z.right;
			transplant(z, z.right);
		} else if (z.right == nil) {
			x = z.left;
			transplant(z, z.left);
		} else {
			y = treeMinimum(z.right);
			yorigcolor = y.color;
			x = y.right;
			if (y.p == z)
				x.p = y;
			else {
				transplant(y, y.right);
				y.right = z.right;
				y.right.p = y;
			}
			transplant(z, y);
			y.left = z.left;
			y.left.p = y;
			y.color = z.color;
		}
		if (yorigcolor == B)
			deleteFixup(x);
		return true;
	}

	void deleteFixup(Node x) {
		while (x != root && x.color == B) {
			if (x == x.p.left) {
				Node w = x.p.right;
				if (w.color == R) {
					w.color = B;
					x.p.color = R;
					rotateLeft(x.p);
					w = x.p.right;
				}
				if (w.left.color == B && w.right.color == B) {
					w.color = R;
					x = x.p;
					continue;
				} else if (w.right.color == B) {
					w.left.color = B;
					w.color = R;
					rotateRight(w);
					w = x.p.right;
				}
				if (w.right.color == R) {
					w.color = x.p.color;
					x.p.color = B;
					w.right.color = B;
					rotateLeft(x.p);
					x = root;
				}
			} else {
				Node w = x.p.left;
				if (w.color == R) {
					w.color = B;
					x.p.color = R;
					rotateRight(x.p);
					w = x.p.left;
				}
				if (w.right.color == B && w.left.color == B) {
					w.color = R;
					x = x.p;
					continue;
				} else if (w.left.color == B) {
					w.right.color = B;
					w.color = R;
					rotateLeft(w);
					w = x.p.left;
				}
				if (w.left.color == R) {
					w.color = x.p.color;
					x.p.color = B;
					w.left.color = B;
					rotateRight(x.p);
					x = root;
				}
			}
		}
		x.color = B;
	}

	public void insertDemo() {
		Scanner scan = new Scanner(System.in);
		while (true) {
			System.out.println("Add items");

			int item;
			Node node;

			item = scan.nextInt();
			while (item != -999) {
				node = new Node(item);
				insert(node);
				item = scan.nextInt();
			}
			printTree(root);
			System.out.println("Pre order");
			printTreepre(root);
			break;
		}
	}

	public void deleteDemo() {
		Scanner scan = new Scanner(System.in);
		System.out.println("Delete items");
		int item;
		Node node;
		item = scan.nextInt();
		node = new Node(item);
		System.out.print("Deleting item " + item);
		if (delete(node)) {
			System.out.print(": deleted!");
		} else {
			System.out.print(": does not exist!");
		}

		System.out.println();
		printTree(root);
		System.out.println("Pre order");
		printTreepre(root);
	}
}